package org.tiger.netty.server.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author lwl
 * @date 2020/10/11 2:51 下午 im通信
 */
public class NioServer {

	private static Logger logger = LoggerFactory.getLogger(NioServer.class);

	private static Map<String, SocketChannel> clientMap = new ConcurrentHashMap<>();

	public static void main(String[] args) throws Exception {
		ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
		serverSocketChannel.configureBlocking(false);// 非阻塞
		ServerSocket serverSocket = serverSocketChannel.socket();
		serverSocket.bind(new InetSocketAddress(8899));

		Selector selector = Selector.open();
		// serversocketchnnel注册到selector
		// io多路复用，文件描述符
		serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

		while (true){
			selector.select();

			Set<SelectionKey> selectionKeys = selector.selectedKeys();

			selectionKeys.forEach(item -> {
				final SocketChannel client;
				try{
					if (item.isAcceptable()){
						ServerSocketChannel server = (ServerSocketChannel) item.channel();

						client = server.accept();
						client.configureBlocking(false);
						client.register(selector, SelectionKey.OP_READ);// 建立好连接 服务端与客户端

						String key = "[" + UUID.randomUUID().toString() + "]";
						clientMap.put(key, client);

					} else if (item.isReadable()){
						client = (SocketChannel) item.channel();
						int byteRead = 0;
						ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
						int read = client.read(byteBuffer);
						if (read > 0){
							byteBuffer.flip();
							Charset charset = Charset.forName("utf-8");
							String message = String.valueOf(charset.decode(byteBuffer).array());
							logger.info("client:" + client + ":message:" + message);

							String sernderKey = null;

							for (Map.Entry<String, SocketChannel> entry : clientMap.entrySet()){
								if (client == entry.getValue()){
									sernderKey = entry.getKey();
									break;
								}
							}

							for (Map.Entry<String, SocketChannel> entry : clientMap.entrySet()){
								SocketChannel channel = entry.getValue();
								ByteBuffer writeBuffer = ByteBuffer.allocate(1024);
								writeBuffer.put((sernderKey + ":" + message).getBytes());
								writeBuffer.flip();
								channel.write(writeBuffer);
							}

						}

					}
					selectionKeys.clear();
				} catch (IOException e){
					logger.error("++++++:", e);
				}

			});

		}

	}

}
